﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Profile;
using COFE.Core;
using COFE.Core.Lister;
using NUnit.Framework;
using System.Data.SqlClient;
using System.Data.Common;
using System.Data;

namespace COFE.Data.Profile
{
    public class DBVolumeManager : IVolumeManager
    {
        #region Constructor

        public DBVolumeManager(IUserProfile userProfile)
        {
            Assert.IsInstanceOf<DBUserProfile>(userProfile);
            _userProfile = userProfile as DBUserProfile;
        }

        #endregion

        #region Methods

        public void Refresh()
        {
            _primaryVolumes.Clear();
            _secondaryVolumes.Clear();

            var profileRootVolume =
                   COFEShared.VolumeRegistrar.LookupRegisterVolume(
                   ProfileRootDirectoryLister.ProfileRootListerKey);
            if (profileRootVolume != null)
                registerVolume(profileRootVolume);  //register in memory only, not database.

            COFEDBShared.DBOperations.ReadDatabase((context) =>
            {                
                var currentUser = (from u in context.Users where u.UserId == _userProfile.UserName select u).FirstOrDefault();
                if (currentUser == null)
                    throw new KeyNotFoundException("User not found or removed.");

                currentUser.Permissions.Load();

                foreach (var perm in currentUser.Permissions)
                {
                    try
                    {
                        var volume = COFEShared.VolumeRegistrar.LookupRegisterVolume(perm.VolumeId);
                        if (volume == null)
                            throw new Exception("Not found - " + perm.VolumeId);
                        registerVolume(volume);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(String.Format("DBVolumeManager: Vol={0} Err={1}", perm.VolumeId, ex.Message));
                    }
                }
            });
        }

        private void checkRefreshed()
        {
            if (!(_refreshed))
            {
                Refresh();
                _refreshed = true;
            }
        }

        void registerVolume(IVolume volume)
        {

            string listerKey = volume.ListerKey;
            if (volume.IsPrimaryDirectoryLister())
            {
                IPrimaryDirectoryLister primaryLister = (IPrimaryDirectoryLister)volume.DirectoryLister;
                lock (_primaryVolumes)
                {
                    if (!_primaryVolumes.Contains(volume))
                        _primaryVolumes.Add(volume);

                    if (primaryLister.RootTempPath != null)
                        TempManager = new DefaultTempManager(primaryLister.RootTempPath, UserProfile.UserName);


                }
            }

            if (volume.IsSecondaryDirectoryLister())
            {
                lock (_secondaryVolumes)
                {
                    if (!_secondaryVolumes.Contains(volume))
                        _secondaryVolumes.Add(volume);
                }
            }
        }

        public void UnregisterVolume(string listerKey)
        {
            checkRefreshed();
            COFEDBShared.DBOperations.UpdateDatabase(
                (context) =>
                {
                    return context.Permissions.FirstOrDefault(
                        p => p.UserId == _userProfile.UserName && p.VolumeId == listerKey);
                },
                (context, origPerm) =>
                {
                    if (origPerm != null)
                    {
                        context.DeleteObject(origPerm);
                        context.SaveChanges();
                    }
                });

            IVolume origVol = null;
            foreach (var pVol in _primaryVolumes)
            {
                if (pVol.ListerKey == listerKey)
                    origVol = pVol;
                break;
            }
            if (origVol != null)
                _primaryVolumes.Remove(origVol);

            if (origVol != null)
            {
                foreach (var vol in _secondaryVolumes)
                    if (vol.ListerKey == listerKey)
                        origVol = vol;
                if (origVol != null)
                    _secondaryVolumes.Remove(origVol);
            }

        }

        public void RegisterVolume(string listerKey)
        {
            checkRefreshed();
            Assert.IsNotNull(UserProfile);
            IVolume volume = COFEShared.VolumeRegistrar.LookupRegisterVolume(listerKey);
            if (volume == null)
                throw new ArgumentException(listerKey + " not found.");
            UnregisterVolume(listerKey);

            var perm = new Permission
            {
                UserId = _userProfile.UserName,
                VolumeId = listerKey,
            };

            COFEDBShared.DBOperations.UpdateDatabase((context) =>
                {
                    if (!context.Permissions.Any((p) =>
                        p.VolumeId == perm.VolumeId && p.UserId == perm.UserId))
                    {
                        context.AddToPermissions(perm);
                        context.SaveChanges();
                    }
                });

            registerVolume(volume);

        }

        #endregion

        #region Data

        private bool _refreshed = false;
        private DBUserProfile _userProfile;
        List<IVolume> _primaryVolumes = new List<IVolume>();
        List<IVolume> _secondaryVolumes = new List<IVolume>();
        ITempManager _tempManager = new NullTempManager();

        #endregion

        #region Public Properties

        

        public IVolume this[string listerKey, bool lookupPrimary = false, bool lookupSecondary = false]
        {
            get
            {
                checkRefreshed();
                if (lookupPrimary)
                    foreach (var vol in _primaryVolumes) if (vol.ListerKey == listerKey) return vol;
                if (lookupSecondary)
                    foreach (var vol in COFEShared.VolumeRegistrar.GetSecondaryVolumes()) if (vol.ListerKey == listerKey) return vol;
                return null;
            }
        }

        public IUserProfile UserProfile { get { return _userProfile; } }
        public ITempManager TempManager { get { return _tempManager; } private set { _tempManager = value; } }
        public IDirectoryInfo[] RootDirectories { get { return PrimaryVolumes.SelectMany((v) => (v.DirectoryLister as IPrimaryDirectoryLister).RootDirectories).ToArray(); } }
        public List<IVolume> PrimaryVolumes { get { checkRefreshed(); return _primaryVolumes; } }
        public List<IVolume> SecondaryVolumes { get { checkRefreshed(); return _secondaryVolumes; } }

        #endregion
    }
}
